﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MongoDB;
using MongoDB.Driver;
using MongoDB.Linq;

namespace ImTag.Mongo
{
    public class Image
    {
        public List<string> Tags;
        public string ImagePath;
    }
    public class MongoManager
    {
        public const string ImTagDB = "ImTag";

        public static bool AddTag(string tag, string filepath)
        {
            var mongo = new MongoDB.Driver.Mongo();
            mongo.Connect();
            var db = mongo[ImTagDB];
            var files = db.GetCollection("Files");
            var tags = db.GetCollection("Tags");
            
            var fileDoc = new Document();
            var tagDoc = new Document();
            fileDoc["Path"] = filepath;
            tagDoc["Name"] = tag;

            var result1 = files.AttachItemToPropertyByList(fileDoc, "Tags", tag);
            var result2 = tags.AttachItemToPropertyByList(tagDoc, "Files", filepath);


            var spec = new Document();
            spec["Path"] = filepath;
            var found = files.Find(spec).Documents.ToArray();
            mongo.Disconnect();
            return result1;
        }
        public static List<Image> SearchImages(IEnumerable<string> tags)
        {
            var mongo = new MongoDB.Driver.Mongo();
            mongo.Connect();
            var db = mongo[ImTagDB];
            var tagsDoc = db.GetCollection("Tags");
            var files = tags.Select(tag =>
                {
                    var spec = new Document();
                    spec["Name"] = tag;
                    return tagsDoc.Find(spec).Documents.SelectMany(d => d["Files"] as List<string>);
                }).Aggregate((f1, f2) => f1.Intersect(f2));

            var filesDoc = db.GetCollection("Files");
            return files.Select(file => 
                {
                    var fileSpec = new Document();
                    fileSpec["Path"] = file;
                    return new Image() { ImagePath = file, Tags = filesDoc.FindOne(fileSpec)["Tags"] as List<string>};
                }).ToList();
        }

        public static List<Image> LoadAllFiles()
        {
            var mongo = new MongoDB.Driver.Mongo();
            mongo.Connect();
            var filesDoc = mongo[ImTagDB].GetCollection("Files");
            return filesDoc.FindAll().Documents.Select(d => new Image() { ImagePath = d["Path"] as string, Tags = d["Tags"] as List<string> }).ToList();
            
        }


        public static List<string> LoadAllTags()
        {
            var mongo = new MongoDB.Driver.Mongo();
            mongo.Connect();
            var filesDoc = mongo[ImTagDB].GetCollection("Tags");
            return filesDoc.FindAll().Documents.Select(d => d["Name"] as string).ToList();
        }


    }

    public static class MongoExtensions
    {
        public static bool AttachItemToPropertyByList(this IMongoCollection collection, Document doc, string property, string newItem)
        {
            var targetFile = collection.FindOne(doc) ?? doc;
            if (targetFile[property] == null)
                targetFile[property] = new string[] { newItem };
            else
            {
                var filetags = targetFile[property] as List<string>;
                if (!filetags.Contains(newItem))
                    filetags.Add(newItem);
                else 
                    return false;
            }
            collection.Update(targetFile);
            return true;
        }
    }
}
